home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / bipl.zip / PROGS.ZIP / IIDECODE.ICN < prev    next >
Text File  |  1993-01-27  |  7KB  |  253 lines

  1. ############################################################################
  2. #
  3. #    File:     iidecode.icn
  4. #
  5. #    Subject:  Program to decode text in style of uudecode
  6. #
  7. #    Author:   Richard L. Goerwitz
  8. #
  9. #    Date:     June 3, 1991
  10. #
  11. ###########################################################################
  12. #
  13. #    Version:  1.8
  14. #
  15. ###########################################################################
  16. #
  17. #  This is an Icon port of the UNIX/C uudecode utility.  Since
  18. #  uudecode is publicly distributable BSD code, I simply grabbed a
  19. #  copy, and rewrote it in Icon.  The only basic functional changes I
  20. #  made to the program were:  1) To simplify the notion of file mode
  21. #  (everything is encoded with 0644 permissions), and 2) to add a
  22. #  command-line switch for xxencoded files (similar to uuencoded
  23. #  files, but capable of passing unscathed through non-ASCII EBCDIC
  24. #  sites).
  25. #
  26. #         usage:  iidecode [infile] [-x]
  27. #
  28. #  Usage is compatible with that of the UNIX uudecode command, i.e. a
  29. #  first (optional) argument gives the name the file to be decoded.
  30. #  If this is omitted, iidecode just uses the standard input.  The -x
  31. #  switch (peculiar to iidecode) forces use of the the xxdecoding
  32. #  algorithm.  If you try to decode an xxencoded file without speci-
  33. #  -x on the command line, iidecode will try to forge ahead anyway.
  34. #  If it thinks you've made a mistake, iidecode will inform you after
  35. #  the decode is finished.
  36. #
  37. #  BUGS:  Slow.  I decided to go for clarity and symmetry, rather than
  38. #  speed, and so opted to do things like use ishift(i,j) instead of
  39. #  straight multiplication (which under Icon v8 is much faster).
  40. #
  41. ############################################################################
  42. #
  43. #  See also: iiencode.icn
  44. #
  45. ############################################################################
  46.  
  47.  
  48. global oversizes
  49.  
  50. procedure main(a)
  51.  
  52.     local ARG, in, out, dest, is_xx
  53.  
  54.     # Check for correct number of args.
  55.     if *a > 2 then {
  56.     write(&errout,"usage:  iidecode [infile] [-x]")
  57.     exit (2)
  58.     }
  59.  
  60.     # Check for optional input filename and -x
  61.     every ARG := !a do {
  62.     if ARG == "-x" then
  63.         is_xx := 1
  64.     else {
  65.         if not (in := open(ARG, "r")) then {
  66.         write(&errout,"Can't open input file, ",a[1],".")
  67.         write(&errout,"usage:  iidecode [infile] [-x]")
  68.         exit(1)
  69.         }
  70.     }
  71.     }
  72.     /in := &input
  73.  
  74.     # Find the "begin" line, and determine the destination file name.
  75.     !in ? {
  76.     tab(match("begin ")) &
  77.     tab(many(&digits))   &    # mode ignored
  78.     tab(many(' '))       &
  79.     dest := trim(tab(0),'\r') # concession to MS-DOS
  80.     }
  81.  
  82.     # If dest is null, the begin line either isn't present, or is
  83.     # corrupt (which necessitates our aborting with an error msg.).
  84.     if /dest then {
  85.     write(&errout,"No begin line.")
  86.     exit(3)
  87.     }
  88.  
  89.     # Tilde expansion is heavily UNIX dependent, and we can't always
  90.     # safely write the file to the current directory.  Our only choice
  91.     # is to abort.
  92.     if match("~",dest) then {
  93.     write(&errout,"Please remove ~ from input file begin line.")
  94.     exit(4)
  95.     }
  96.        
  97.     out := open(dest, "wu")
  98.     decode(in, out, is_xx)    # decode checks for "end" line
  99.     if not match("end", !in) then {
  100.     write(&errout,"No end line.\n")
  101.     exit(5)
  102.     }
  103.  
  104.     # Check global variable oversizes (set by DEC) to see if we used the
  105.     # correct decoding algorithm.
  106.     if \is_xx then {
  107.     if oversizes = 0 then {
  108.         write(&errout, "Input file appears to have been uuencoded.")
  109.         write(&errout, "Try invoking iidecode without the -x arg.")
  110.     }
  111.     }
  112.     else {
  113.     if oversizes > 1 then {
  114.         write(&errout, "Input file is either corrupt, or xxencoded.")
  115.         write(&errout, "Please check the output; try the -x option.")
  116.     }
  117.     }
  118.  
  119.     every close(\in | out)
  120.  
  121.     exit(0)
  122.  
  123. end
  124.  
  125.  
  126.  
  127. procedure decode(in, out, is_xx)
  128.     
  129.     # Copy from in to out, decoding as you go along.
  130.  
  131.     local line, chunk, n
  132.  
  133.     if \is_xx then
  134.     DEC := xxDEC
  135.  
  136.     while line := read(in) do {
  137.  
  138.     if *line = 0 then {
  139.         write(&errout,"Short file.\n")
  140.         exit(10)
  141.     }
  142.  
  143.     line ? {
  144.         n := DEC(ord(move(1)))
  145.  
  146.         if not ((*line-1) % 4 = 0, n <= ((*line / 4)*3)) then {
  147.         write(&errout,"Short and/or corrupt line:\n",line)
  148.         if /is_xx & oversizes > 1 then
  149.             write(&errout,"Try -x option?")
  150.                 exit(15)
  151.             }
  152.  
  153.         # Uuencode signals the end of the coded text by a space
  154.         # and a line (i.e. a zero-length line, coded as a space).
  155.         if n <= 0 then break
  156.         
  157.         while (n > 0) do {
  158.         chunk := move(4) | tab(0)
  159.         outdec(chunk, out, n)
  160.         n -:= 3
  161.         }
  162.     }
  163.     }
  164.     
  165.     return
  166.  
  167. end
  168.  
  169.  
  170.  
  171. procedure outdec(s, f, n)
  172.  
  173.     # Output a group of 3 bytes (4 input characters).  N is used to
  174.     # tell us not to output all of the chars at the end of the file.
  175.  
  176.     local c1, c2, c3
  177.  
  178.     c1 := iand(
  179.            ior(
  180.            ishift(DEC(ord(s[1])),+2),
  181.            ishift(DEC(ord(s[2])),-4)
  182.            ),
  183.            8r0377)
  184.     c2 := iand(
  185.            ior(
  186.            ishift(DEC(ord(s[2])),+4),
  187.            ishift(DEC(ord(s[3])),-2)
  188.            ),
  189.            8r0377)
  190.     c3 := iand(
  191.            ior(
  192.            ishift(DEC(ord(s[3])),+6),
  193.            DEC(ord(s[4]))
  194.            ),
  195.            8r0377)
  196.  
  197.     if (n >= 1) then
  198.     writes(f,char(c1))
  199.     if (n >= 2) then
  200.     writes(f,char(c2))
  201.     if (n >= 3) then
  202.     writes(f,char(c3))
  203.  
  204. end    
  205.  
  206.  
  207.  
  208. procedure DEC(c)
  209.  
  210.     # global oversizes
  211.     initial oversizes := 0
  212.  
  213.     # Count characters lexically greater or equal to 'a.'
  214.     # If we get a lot of these, the file is corrupt, or perhaps
  215.     # xxencoded (in which case -x should have been specified).
  216.     if c >= 97 then
  217.     oversizes +:= 1
  218.  
  219.     # Subtract 32 and mask off seventh and higher bits.
  220.     return iand(c - 32, 8r077)
  221.  
  222. end
  223.  
  224.  
  225.  
  226. procedure xxDEC(c)
  227.  
  228.     local k, ordval, new_c
  229.     static ordtbl
  230.     # global oversizes
  231.     initial {
  232.     ordval := -1
  233.     ordtbl := table()
  234.     every k := ord(!"+-0123456789ABCDEFGHIJKLMNOPQRST_
  235.                  UVWXYZabcdefghijklmnopqrstuvwxyz")
  236.     do insert(ordtbl, k, ordval +:= 1)
  237.     oversizes := 0
  238.     }
  239.  
  240.     # Mask off eighth and higher bits.
  241.     new_c := iand(c, 8r177)
  242.  
  243.     # Count characters lexically greater or equal to 'a.'
  244.     # If we find none of these, the file probably wasn't xxencoded.
  245.     if new_c >= 97 then
  246.     oversizes +:= 1
  247.  
  248.     # Map to 0-63 range (00111111 or less), mask off extra bits.
  249.     return iand(\ordtbl[new_c], 8r077) |
  250.     stop("Garbled or non-xxencoded file.")
  251.  
  252. end
  253.